home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pctchnqs / 1991 / number2 / l1.c < prev    next >
Text File  |  1991-03-23  |  12KB  |  288 lines

  1. /* Split screen VGA animation program. Performs page flipping in the
  2. top portion of the screen while displaying non-page flipped
  3. information in the split screen at the bottom of the screen.
  4. Compiled with Borland C++ 2.0 in C compilation mode. */
  5.  
  6. #include <stdio.h>
  7. #include <conio.h>
  8. #include <dos.h>
  9. #include <math.h>
  10.  
  11. #define SCREEN_SEG         0xA000
  12. #define SCREEN_PIXWIDTH    640   /* in pixels */
  13. #define SCREEN_WIDTH       80    /* in bytes */
  14. #define SPLIT_START_LINE   339
  15. #define SPLIT_LINES        141
  16. #define NONSPLIT_LINES     339
  17. #define SPLIT_START_OFFSET 0
  18. #define PAGE0_START_OFFSET (SPLIT_LINES*SCREEN_WIDTH)
  19. #define PAGE1_START_OFFSET ((SPLIT_LINES+NONSPLIT_LINES)*SCREEN_WIDTH)
  20. #define CRTC_INDEX   0x3D4 /* CRT Controller Index register */
  21. #define CRTC_DATA    0x3D5 /* CRT Controller Data register */
  22. #define OVERFLOW     0x07  /* index of CRTC reg holding bit 8 of the
  23.                               line the split screen starts after */
  24. #define MAX_SCAN     0x09  /* index of CRTC reg holding bit 9 of the
  25.                               line the split screen starts after */
  26. #define LINE_COMPARE 0x18  /* index of CRTC reg holding lower 8 bits
  27.                               of line split screen starts after */
  28. #define NUM_BUMPERS  (sizeof(Bumpers)/sizeof(bumper))
  29. #define BOUNCER_COLOR 15
  30. #define BACK_COLOR   1     /* playfield background color */
  31.  
  32. typedef struct {  /* one solid bumper to be bounced off of */
  33.    int LeftX,TopY,RightX,BottomY;
  34.    int Color;
  35. } bumper;
  36.  
  37. typedef struct {     /* one bit pattern to be used for drawing */
  38.    int WidthInBytes;
  39.    int Height;
  40.    unsigned char *BitPattern;
  41. } image;
  42.  
  43. typedef struct {  /* one bouncing object to move around the screen */
  44.    int LeftX,TopY;         /* location */
  45.    int Width,Height;       /* size in pixels */
  46.    int DirX,DirY;          /* motion vectors */
  47.    int CurrentX[2],CurrentY[2]; /* current location in each page */
  48.    int Color;              /* color in which to be drawn */
  49.    image *Rotation0;       /* rotations for handling the 8 possible */
  50.    image *Rotation1;       /* intrabyte start address at which the */
  51.    image *Rotation2;       /* left edge can be */
  52.    image *Rotation3;
  53.    image *Rotation4;
  54.    image *Rotation5;
  55.    image *Rotation6;
  56.    image *Rotation7;
  57. } bouncer;
  58.  
  59. void main(void);
  60. void DrawBumperList(bumper *, int, unsigned int);
  61. void DrawSplitScreen(void);
  62. void EnableSplitScreen(void);
  63. void MoveBouncer(bouncer *, bumper *, int);
  64. extern void DrawRect(int,int,int,int,int,unsigned int,unsigned int);
  65. extern void ShowPage(unsigned int);
  66. extern void DrawImage(int,int,image **,int,unsigned int,unsigned int);
  67. extern void ShowBounceCount(void);
  68. extern void TextUp(char *,int,int,unsigned int,unsigned int);
  69. extern void SetBIOS8x8Font(void);
  70.  
  71. /* All bumpers in the playfield */
  72. bumper Bumpers[] = {
  73.    {0,0,19,339,2}, {0,0,639,19,2}, {620,0,639,339,2},
  74.    {0,320,639,339,2}, {60,48,79,67,12}, {60,108,79,127,12},
  75.    {60,168,79,187,12}, {60,228,79,247,12}, {120,68,131,131,13},
  76.    {120,188,131,271,13}, {240,128,259,147,14}, {240,192,259,211,14},
  77.    {208,160,227,179,14}, {272,160,291,179,14}, {228,272,231,319,11},
  78.    {192,52,211,55,11}, {302,80,351,99,12}, {320,260,379,267,13},
  79.    {380,120,387,267,13}, {420,60,579,63,11}, {428,110,571,113,11},
  80.    {420,160,579,163,11}, {428,210,571,213,11}, {420,260,579,263,11} };
  81.  
  82. /* Image for bouncing object when left edge is aligned with bit 7 */
  83. unsigned char _BouncerRotation0[] = {
  84.    0xFF,0x0F,0xF0, 0xFE,0x07,0xF0, 0xFC,0x03,0xF0, 0xFC,0x03,0xF0,
  85.    0xFE,0x07,0xF0, 0xFF,0xFF,0xF0, 0xCF,0xFF,0x30, 0x87,0xFE,0x10,
  86.    0x07,0x0E,0x00, 0x07,0x0E,0x00, 0x07,0x0E,0x00, 0x07,0x0E,0x00,
  87.    0x87,0xFE,0x10, 0xCF,0xFF,0x30, 0xFF,0xFF,0xF0, 0xFE,0x07,0xF0,
  88.    0xFC,0x03,0xF0, 0xFC,0x03,0xF0, 0xFE,0x07,0xF0, 0xFF,0x0F,0xF0};
  89. image BouncerRotation0 = {3, 20, _BouncerRotation0};
  90.  
  91. /* Image for bouncing object when left edge is aligned with bit 3 */
  92. unsigned char _BouncerRotation4[] = {
  93.    0x0F,0xF0,0xFF, 0x0F,0xE0,0x7F, 0x0F,0xC0,0x3F, 0x0F,0xC0,0x3F,
  94.    0x0F,0xE0,0x7F, 0x0F,0xFF,0xFF, 0x0C,0xFF,0xF3, 0x08,0x7F,0xE1,
  95.    0x00,0x70,0xE0, 0x00,0x70,0xE0, 0x00,0x70,0xE0, 0x00,0x70,0xE0,
  96.    0x08,0x7F,0xE1, 0x0C,0xFF,0xF3, 0x0F,0xFF,0xFF, 0x0F,0xE0,0x7F,
  97.    0x0F,0xC0,0x3F, 0x0F,0xC0,0x3F, 0x0F,0xE0,0x7F, 0x0F,0xF0,0xFF};
  98. image BouncerRotation4 = {3, 20, _BouncerRotation4};
  99.  
  100. /* Initial settings for bouncing object. Only 2 rotations are needed
  101.    because the object moves 4 pixels horizontally at a time */
  102. bouncer Bouncer = {156,60,20,20,4,4,156,156,60,60,BOUNCER_COLOR,
  103.    &BouncerRotation0,NULL,NULL,NULL,&BouncerRotation4,NULL,NULL,NULL};
  104. unsigned int PageStartOffsets[2] =
  105.    {PAGE0_START_OFFSET,PAGE1_START_OFFSET};
  106. unsigned int BounceCount;
  107.  
  108. void main() {
  109.    int DisplayedPage, NonDisplayedPage, Done, i;
  110.    union REGS regset;
  111.  
  112.    regset.x.ax = 0x0012; /* set display to 640x480 16-color mode */
  113.    int86(0x10, ®set, ®set);
  114.    SetBIOS8x8Font();    /* set the pointer to the BIOS 8x8 font */
  115.    EnableSplitScreen(); /* turn on the split screen */
  116.  
  117.    /* Display page 0 above the split screen */
  118.    ShowPage(PageStartOffsets[DisplayedPage = 0]);
  119.  
  120.    /* Clear both pages to background and draw bumpers in each page */
  121.    for (i=0; i<2; i++) {
  122.       DrawRect(0,0,SCREEN_PIXWIDTH-1,NONSPLIT_LINES-1,BACK_COLOR,
  123.             PageStartOffsets[i],SCREEN_SEG);
  124.       DrawBumperList(Bumpers,NUM_BUMPERS,PageStartOffsets[i]);
  125.    }
  126.  
  127.    DrawSplitScreen();   /* draw the static split screen info */
  128.    BounceCount = 0;
  129.    ShowBounceCount();   /* put up the initial zero count */
  130.  
  131.    /* Draw the bouncing object at its initial location */
  132.    DrawImage(Bouncer.LeftX,Bouncer.TopY,&Bouncer.Rotation0,
  133.          Bouncer.Color,PageStartOffsets[DisplayedPage],SCREEN_SEG);
  134.  
  135.    /* Move the object, draw it in the nondisplayed page, and flip the
  136.       page until Esc is pressed */
  137.    Done = 0;
  138.    do {
  139.       NonDisplayedPage = DisplayedPage ^ 1;
  140.       /* Erase at current location in the nondisplayed page */
  141.       DrawRect(Bouncer.CurrentX[NonDisplayedPage],
  142.             Bouncer.CurrentY[NonDisplayedPage],
  143.             Bouncer.CurrentX[NonDisplayedPage]+Bouncer.Width-1,
  144.             Bouncer.CurrentY[NonDisplayedPage]+Bouncer.Height-1,
  145.             BACK_COLOR,PageStartOffsets[NonDisplayedPage],SCREEN_SEG);
  146.       /* Move the bouncer */
  147.       MoveBouncer(&Bouncer, Bumpers, NUM_BUMPERS);
  148.       /* Draw at the new location in the nondisplayed page */
  149.       DrawImage(Bouncer.LeftX,Bouncer.TopY,&Bouncer.Rotation0,
  150.             Bouncer.Color,PageStartOffsets[NonDisplayedPage],
  151.             SCREEN_SEG);
  152.       /* Remember where the bouncer is in the nondisplayed page */
  153.       Bouncer.CurrentX[NonDisplayedPage] = Bouncer.LeftX;
  154.       Bouncer.CurrentY[NonDisplayedPage] = Bouncer.TopY;
  155.       /* Flip to the page we just drew into */
  156.       ShowPage(PageStartOffsets[DisplayedPage = NonDisplayedPage]);
  157.       /* Respond to any keystroke */
  158.       if (kbhit()) {
  159.          switch (getch()) {
  160.             case 0x1B:           /* Esc to end */
  161.                Done = 1; break;
  162.             case 0:              /* branch on the extended code */
  163.                switch (getch()) {
  164.                   case 0x48:  /* nudge up */
  165.                      Bouncer.DirY = -abs(Bouncer.DirY); break;
  166.                   case 0x4B:  /* nudge left */
  167.                      Bouncer.DirX = -abs(Bouncer.DirX); break;
  168.                   case 0x4D:  /* nudge right */
  169.                      Bouncer.DirX = abs(Bouncer.DirX); break;
  170.                   case 0x50:  /* nudge down */
  171.                      Bouncer.DirY = abs(Bouncer.DirY); break;
  172.                }
  173.                break;
  174.             default:
  175.                break;
  176.          }
  177.       }
  178.    } while (!Done);   
  179.  
  180.    /* Restore text mode and done */
  181.    regset.x.ax = 0x0003;
  182.    int86(0x10, ®set, ®set);
  183. }
  184.  
  185. /* Draws the specified list of bumpers into the specified page */
  186. void DrawBumperList(bumper * Bumpers, int NumBumpers,
  187.       unsigned int PageStartOffset)
  188. {
  189.    int i;
  190.  
  191.    for (i=0; i<NumBumpers; i++,Bumpers++) {
  192.       DrawRect(Bumpers->LeftX,Bumpers->TopY,Bumpers->RightX,
  193.             Bumpers->BottomY,Bumpers->Color,PageStartOffset,
  194.             SCREEN_SEG);
  195.    }
  196. }
  197.  
  198. /* Displays the current bounce count */
  199. void ShowBounceCount() {
  200.    char CountASCII[7];
  201.  
  202.    itoa(BounceCount,CountASCII,10); /* convert the count to ASCII */
  203.    TextUp(CountASCII,344,64,SPLIT_START_OFFSET,SCREEN_SEG);
  204. }
  205.  
  206. /* Frames the split screen and fills it with various text */
  207. void DrawSplitScreen() {
  208.    DrawRect(0,0,SCREEN_PIXWIDTH-1,SPLIT_LINES-1,0,SPLIT_START_OFFSET,
  209.          SCREEN_SEG);
  210.    DrawRect(0,1,SCREEN_PIXWIDTH-1,4,15,SPLIT_START_OFFSET,
  211.          SCREEN_SEG);
  212.    DrawRect(0,SPLIT_LINES-4,SCREEN_PIXWIDTH-1,SPLIT_LINES-1,15,
  213.          SPLIT_START_OFFSET,SCREEN_SEG);
  214.    DrawRect(0,1,3,SPLIT_LINES-1,15,SPLIT_START_OFFSET,SCREEN_SEG);
  215.    DrawRect(SCREEN_PIXWIDTH-4,1,SCREEN_PIXWIDTH-1,SPLIT_LINES-1,15,
  216.          SPLIT_START_OFFSET,SCREEN_SEG);
  217.    TextUp("This is the split screen area...",8,8,SPLIT_START_OFFSET,
  218.          SCREEN_SEG);
  219.    TextUp("Bounces: ",272,64,SPLIT_START_OFFSET,SCREEN_SEG);
  220.    TextUp("\033: nudge left",520,78,SPLIT_START_OFFSET,SCREEN_SEG);
  221.    TextUp("\032: nudge right",520,90,SPLIT_START_OFFSET,SCREEN_SEG);
  222.    TextUp("\031: nudge down",520,102,SPLIT_START_OFFSET,SCREEN_SEG);
  223.    TextUp("\030: nudge up",520,114,SPLIT_START_OFFSET,SCREEN_SEG);
  224.    TextUp("Esc to end",520,126,SPLIT_START_OFFSET,SCREEN_SEG);
  225. }
  226.  
  227. /* Turn on the split screen at the desired line (minus 1 because the
  228.    split screen starts *after* the line specified by the LINE_COMPARE
  229.    register) (bit 8 of the split screen start line is stored in the
  230.    Overflow register, and bit 9 is in the Maximum Scan Line reg) */
  231. void EnableSplitScreen() {
  232.    outp(CRTC_INDEX, LINE_COMPARE);
  233.    outp(CRTC_DATA, (SPLIT_START_LINE - 1) & 0xFF);
  234.    outp(CRTC_INDEX, OVERFLOW);
  235.    outp(CRTC_DATA, (((((SPLIT_START_LINE - 1) & 0x100) >> 8) << 4) |
  236.          (inp(CRTC_DATA) & ~0x10)));
  237.    outp(CRTC_INDEX, MAX_SCAN);
  238.    outp(CRTC_DATA, (((((SPLIT_START_LINE - 1) & 0x200) >> 9) << 6) |
  239.          (inp(CRTC_DATA) & ~0x40)));
  240. }
  241.  
  242. /* Moves the bouncer, bouncing if bumpers are hit */
  243. void MoveBouncer(bouncer *Bouncer, bumper *BumperPtr, int NumBumpers) {
  244.    int NewLeftX, NewTopY, NewRightX, NewBottomY, i;
  245.  
  246.    /* Move to new location, bouncing if necessary */
  247.    NewLeftX = Bouncer->LeftX + Bouncer->DirX;   /* new coords */
  248.    NewTopY = Bouncer->TopY + Bouncer->DirY;
  249.    NewRightX = NewLeftX + Bouncer->Width - 1;
  250.    NewBottomY = NewTopY + Bouncer->Height - 1;
  251.    /* Compare the new location to all bumpers, checking for bounce */
  252.    for (i=0; i<NumBumpers; i++,BumperPtr++) {
  253.       /* If moving puts the bouncer inside this bumper, bounce */
  254.       if (  (NewLeftX <= BumperPtr->RightX) &&
  255.             (NewRightX >= BumperPtr->LeftX) &&
  256.             (NewTopY <= BumperPtr->BottomY) &&
  257.             (NewBottomY >= BumperPtr->TopY) ) {
  258.          /* The bouncer has tried to move into this bumper; figure
  259.             out which edge(s) it crossed, and bounce accordingly */
  260.          if (((Bouncer->LeftX > BumperPtr->RightX) &&
  261.                (NewLeftX <= BumperPtr->RightX)) ||
  262.                (((Bouncer->LeftX + Bouncer->Width - 1) <
  263.                BumperPtr->LeftX) &&
  264.                (NewRightX >= BumperPtr->LeftX))) {
  265.             Bouncer->DirX = -Bouncer->DirX;  /* bounce horizontally */
  266.             NewLeftX = Bouncer->LeftX + Bouncer->DirX;
  267.          }
  268.          if (((Bouncer->TopY > BumperPtr->BottomY) &&
  269.                (NewTopY <= BumperPtr->BottomY)) ||
  270.                (((Bouncer->TopY + Bouncer->Height - 1) <
  271.                BumperPtr->TopY) &&
  272.                (NewBottomY >= BumperPtr->TopY))) {
  273.             Bouncer->DirY = -Bouncer->DirY; /* bounce vertically */
  274.             NewTopY = Bouncer->TopY + Bouncer->DirY;
  275.          }
  276.          /* Update the bounce count display; turn over at 10000 */
  277.          if (++BounceCount >= 10000) {
  278.             TextUp("0    ",344,64,SPLIT_START_OFFSET,SCREEN_SEG);
  279.             BounceCount = 0;
  280.          } else {
  281.             ShowBounceCount();
  282.          }
  283.       }
  284.    }
  285.    Bouncer->LeftX = NewLeftX; /* set the final new coordinates */
  286.    Bouncer->TopY = NewTopY;
  287. }
  288.